#include <fmt/color.h>
#include <fmt/core.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/spdlog.h>

#include <string>

namespace py = pybind11;
using namespace pybind11::literals;

int main()
{
#if 0
// 基本控制台日志
    spdlog::info("这是一条 info 级别的日志");
    spdlog::warn("这是一条 warn 级别的日志");
    spdlog::error("这是一条 error 级别的日志");
    spdlog::critical("这是一条 critical 级别的日志");

    // 格式化日志
    int version = 1;
    std::string name = "spdlog demo";
    spdlog::info("程序名称: {}, 版本: {}", name, version);

    // 尝试创建文件日志（注意：实际运行时可能需要有写权限的路径）
    try
    {
        auto file_logger = spdlog::basic_logger_mt("file_logger", "logs/demo.log");
        file_logger->info("这条日志会被写入到文件中");
        spdlog::info("文件日志器已创建");
    }
    catch (const spdlog::spdlog_ex &ex)
    {
        spdlog::error("无法创建文件日志器: {}", ex.what());
    }
#endif

    //std::string pybind_name{MY_PY_BIND_NAME};
    //spdlog::info("pybind_name: {}", pybind_name);

    return 0;
}

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxx simple function
//https://pybind11.readthedocs.io/en/stable/basics.html#keyword-arguments
int add(int i, int j) { return i + j; }

struct Pet
{
    Pet(const std::string &name) : name(name) {}
    void setName(const std::string &name_) { name = name_; }
    const std::string &getName() const { return name; }

    static std::string ClassName() { return "Pet"; }

    std::string name;
};

PYBIND11_MODULE(MY_PY_BIND, m, py::mod_gil_not_used())
{
    m.doc() = "pybind11 example plugin";  // optional module docstring

    ///================= First steps
    // https://pybind11.readthedocs.io/en/stable/basics.html#keyword-arguments
    m.def("add", &add, "A function that adds two numbers");

    m.def("add_key", &add, "A function which adds two numbers", py::arg("i"), py::arg("j"));

    m.def("add_key_short", &add, "i"_a, "j"_a);

    m.def("add3", &add, "A function which adds two numbers", py::arg("i") = 1, py::arg("j") = 2);
    // shorthand
    m.def("add4", &add, "i"_a = 1, "j"_a = 2);

    m.attr("the_answer") = 42;
    py::object world = py::cast("World");
    m.attr("what") = world;

    ///================= Object-oriented code
    // https://pybind11.readthedocs.io/en/stable/classes.html
    py::class_<Pet>(m, "Pet")                      //
        .def(py::init<const std::string &>())      //
        .def("setName", &Pet::setName)             //
        .def("getName", &Pet::getName)             //
        .def_readwrite("name", &Pet::name)         //
        .def_static("ClassName", &Pet::ClassName)  //
        .def("__repr__",                           //
             [](const Pet &a) { return "<example.Pet named '" + a.name + "'>"; });
    ;
}
